
from view.endSrc.MySqlConn import MySqlConn

from view.endSrc.tObserver import tObserver
from view.endSrc.Observer import Observer
from view.endSrc.Dataset import Dataset
from view.endSrc.MyTools import MyTools

class ObserverGenerator:

    def __init__(self):

        self.dbconn = None
        self.logger = None
        self.sessionId = None

        self.clusterEstimatorClassName = None
        self.one2oneClassName = None
        self.n2nClassName = None
        self.filterCfgJSONDict = None
        self.mixedParamsCfgJSONDict = None

    def setConfig(self, sqlConn: MySqlConn, sessionId, datasetDBId,
                  clusterEstimatorClassName,
                  one2oneClassName, n2nClassName,
                  filterCfgJSONDict, mixedParamsCfgJSONDict=None):
        '''

        :param sqlConn:
        :param datasetDBId:
        :param clusterEstimatorClassName:
        :param one2oneClassName:
        :param n2nClassName:
        :param filterCfgJSONDict:
        :param mixedParamsCfgJSONDict:
        :return: True if ok
        '''

        self.dbconn = sqlConn
        self.logger = sqlConn.logger

        self.clusterEstimatorClassName = clusterEstimatorClassName
        self.one2oneClassName = one2oneClassName
        self.n2nClassName = n2nClassName

        self.filterCfgJSONDict = filterCfgJSONDict
        self.mixedParamsCfgJSONDict = mixedParamsCfgJSONDict


        # load dataset from DB
        self.dataset = Dataset.fromDB(self.dbconn, datasetDBId)
        if self.dataset is None:
            tmp = 'ObserverGenerator.setConfig..failed to load dataset'
            tmp += ' from DB where datasetDBId = ' + str(datasetDBId)
            self.logger.write(tmp)
            return False

        # 3) dynamically load distance functions
        try:
            p2pName = self.one2oneClassName
            cls = MyTools.getClass(p2pName + '.' + p2pName)
            self.p2pFun = cls()
        except Exception as e:
            self.logger.write('ObserverGenerator.setConfig..failed to new an object of One2One distance class: ' + p2pName)
            return False

        try:
            n2nName = self.n2nClassName
            cls = MyTools.getClass(n2nName + '.' + n2nName)
            self.n2nFun = cls()
        except Exception as e:
            self.logger.write('ObserverGenerator.setConfig..failed to new an object of N2N distances class: ' + n2nName)
            return False

        self.sessionId = sessionId
        return True


    def createObservers(self, numOfObservers):
        '''
            return list of observers
        :param numOfObservers:
        :return:
        '''
        print('createObservers...')

        assert self.sessionId is not None, 'please call setConfig first'

        lst = []
        vpList = self.getViewPointList(self.dataset, numOfObservers, self.p2pFun, self.n2nFun)
        for vp in vpList:
            table = tObserver(self.dbconn)
            dbId = table.createRow(self.sessionId,
                            self.clusterEstimatorClassName,
                            vp,
                            self.one2oneClassName,
                            self.n2nClassName,
                            self.filterCfgJSONDict,
                            self.mixedParamsCfgJSONDict)

            if dbId is None:
                tmp = 'ObserverGenerator.createObservers..failed to create tObserver for'
                tmp += ' viewpoint: ' + str(vp)
                self.logger.write(tmp)
                return False

            ob = Observer()
            if not ob.setConfig(self.dataset, self.dbconn, dbId):
                tmp = 'ObserverGenerator.createObservers..failed to create Observer for'
                tmp += ' dbId: ' + str(dbId)
                self.logger.write(tmp)
                return False
            lst.append(ob)

        print('createObservers finish')
        return lst

    def getViewPointList(self, dataset, nViewPoints, p2pFun, n2nFun):

        assert False, 'ObserverGenerator.getViewPoints must be implemented by subclasses'
